﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace Comm.Security
{
    public class ServiceLicense
    {
        /// <summary>
        /// 方案服务许可验证
        /// </summary>
        const string CONST_LINCENSE_FILENAME = "lincense.lce";

        private XDocument xDoc;

        /// <summary>
        /// 设置许可文件文件夹路径
        /// </summary>
        public static string LicenseDir
        {
            private get;
            set;
        }

        private static object LicenseObject = new object();

        /// <summary>
        /// 检查是否授权（如果没有超过最大授权数，将自动授权。
        /// </summary>
        /// <param name="sn">需要查询的硬盘序列号，多个硬盘序列号，使用逗号分隔传入</param>
        /// <returns></returns>
        public bool IsAuthorized(string sn)
        {
            int count = int.Parse(xDoc.Descendants("Item").Where((xe) => xe.Attribute("Name").Value == "Count").First().Attribute("Value").Value);

            if (count == -1) return true;

            string[] tmparr = sn.Split(',');

            foreach (string s in xDoc.Descendants("Item")
                                     .Where((xe) => xe.Attribute("Name").Value == "Sn")
                                     .Select((xe) => xe.Attribute("Value").Value))
            {
                foreach (string tmp in tmparr)
                {
                    if (s == tmp.Trim()) return true;
                }
            }

            lock (LicenseObject)
            {
                if (xDoc.Descendants("Item").Where((xe) => xe.Attribute("Name").Value == "Sn").Count() > int.Parse(xDoc.Descendants("Item").Where((xe) => xe.Attribute("Name").Value == "Count").First().Attribute("Value").Value)) return false;

                xDoc.Element("License").Add(new XElement("Item",
                                                            new XAttribute("Name", "Sn"),
                                                            new XAttribute("Value", tmparr[0].Trim())
                                                         )
                                            );

                byte[] buffer = Encoding.UTF8.GetBytes(xDoc.ToString());

                buffer = Crypt.SchemeCrypt.Instance.Encrypt(buffer);

                string path = string.Format(@"{0}\{1}", LicenseDir == "" ? System.Environment.CurrentDirectory : LicenseDir, CONST_LINCENSE_FILENAME);

                using (System.IO.FileStream fs = new System.IO.FileStream(path, System.IO.FileMode.Create, System.IO.FileAccess.Write))
                {

                    fs.Write(buffer, 0, buffer.Length);

                    fs.Close();
                }
            }
            return true;
        }

        /// <summary>
        /// 不允许外部创建实例
        /// </summary>
        private ServiceLicense(XDocument xdoc)
        {
            xDoc = xdoc;
        }

        /// <summary>
        /// 创建一个服务端许可文件
        /// </summary>
        /// <param name="MaxLicenseCount">最大许可客户端数量，如果输入-1则无最大许可限制</param>
        /// <param name="hdsn">硬盘顺序号</param>
        /// <returns></returns>
        public static bool Create(int MaxLicenseCount, string hdsn)
        {
            XDocument xDoc = new XDocument();

            xDoc.Add(new XElement("License",
                                  new XElement("Item",
                                               new XAttribute("Name", "Count"),
                                               new XAttribute("Value", MaxLicenseCount)
                                               ),
                                  new XElement("Item",
                                      new XAttribute("Name", "Hdsn"),
                                      new XAttribute("Value", hdsn))
                                      )
                     );
            try
            {
                byte[] buffer = Encoding.UTF8.GetBytes(xDoc.ToString());
                buffer = Crypt.SchemeCrypt.Instance.Encrypt(buffer);
                string path = string.Format(@"{0}\{1}", LicenseDir == "" ? System.Environment.CurrentDirectory : LicenseDir, CONST_LINCENSE_FILENAME);
                using (System.IO.FileStream fs = new System.IO.FileStream(path, System.IO.FileMode.Create, System.IO.FileAccess.Write))
                {
                    fs.Write(buffer, 0, buffer.Length);
                    fs.Close();
                }
            }
            catch (Exception e)
            {
                throw e;
            }
            return true;

        }

        /// <summary>
        /// 加载许可文件,如果成功，返回许可对象实例，如果失败则返回NULL
        /// </summary>
        /// <param name="dir">文件加载父域文件夹路径</param>
        /// <returns></returns>
        public static ServiceLicense Load()
        {
            string path = string.Format(@"{0}\{1}", LicenseDir, CONST_LINCENSE_FILENAME);

            if (!System.IO.File.Exists(path))
            {
                return null;
            }

            try
            {
                byte[] buff;
                using (System.IO.FileStream fs = new System.IO.FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read))
                {
                    buff = new byte[fs.Length];

                    fs.Read(buff, 0, buff.Length);

                    fs.Close();
                }

                buff = Crypt.SchemeCrypt.Instance.Decrypt(buff);

                string xml = Encoding.UTF8.GetString(buff);

                XDocument xDoc = XDocument.Parse(xml);

                if (xDoc.Descendants("Item").Where((xe) => xe.Attribute("Name").Value == "Count").Count() != 1) return null;

                int.Parse(xDoc.Descendants("Item").Where((xe) => xe.Attribute("Name").Value == "Count").First().Attribute("Value").Value);

                //比较硬盘序列号，是否相同 
                string hdsn = xDoc.Descendants("Item").Where((xe) => xe.Attribute("Name").Value == "Hdsn").First().Attribute("Value").Value;

                string currentHdsn = HardDisk.HardDiskHelper.GetAllHardDiskSN().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)[0];
                if (hdsn.Equals(currentHdsn, StringComparison.OrdinalIgnoreCase) == false)
                {
                    throw new Exception();
                }
                return new ServiceLicense(xDoc);

            }
            catch { return null; }
        }

    }
}
